
let BaseView = require('./ui2/BaseView');
let ControlView = require('./ui2/controlView');
let InspcetView = require('./ui2/InspectView');

require('./ui2/css/debug.css');
require('./ui2/css/pubs.css');

let UIConstants = require('./ui2/ui_constants');

let EditChainState = require('./state/editChainState');
let EditHoleBridge = require('./state/editHoleBridge');
let EditObjState = require('./state/editObjState');
let ViewState = require('./state/viewState');
let settings = require('./settings');

// let XDoMgr = require('./cmds/xdoMgr');

let History = require('./cmds/history');

function onKeyDown(event) {
    console.log('keydown called!');
    let keycode = event.keyCode;
    if(keycode === cc.macro.KEY.z &&
        event.ctrlKey &&
        !event.shiftKey &&
        !event.metaKey){
        cc.log('激活 Ctrl+Z');

        //
        if(!editor.isEditChainState()){
            cc.log('只在编辑轨道模式下可以使用undo/redo');
            return;
        }

        editor.history.undo();
    }else if(keycode === cc.macro.KEY.z &&
        event.ctrlKey &&
        event.shiftKey &&
        !event.metaKey){
        cc.log('激活 Ctrl+Shift+Z');
        if(!editor.isEditChainState()){
            cc.log('只在编辑轨道模式下可以使用undo/redo');
            return;
        }
        editor.history.redo();
    }
}


class EditorView extends BaseView{

    constructor() {
        super();

        window.editor = this;
        this._gameApp  = G.gameMap;
        this._bInited = false;

        this.rootEl = document.body;

        //--------------
        // 开始绑定数据?????

        // cocos gameDiv
        this._gameDiv = document.getElementById('GameDiv');

        let canvas = document.getElementById('GameCanvas');
        this._gameDiv.addEventListener('mouseenter',()=>{
            // 获得focus
            canvas.focus();
        },false);

        // 让 window 和 canvas 都来监听 key事件
        window.addEventListener('keydown',onKeyDown,false);
        canvas.addEventListener('keydown',onKeyDown,false);

        this.history = new History();
    }

    initEditor(){
        this.inspectView = new InspcetView();
        this.addView(this.inspectView);

        // 构建整个界面
        this.controlView = new ControlView();
        this.addView(this.controlView);

        this._initStates();

        this.initDAD();
    }

    _initStates(){
        this.editChainState = new EditChainState();
        this.editHoleBridgeState = new EditHoleBridge();
        this.editObjState = new EditObjState();
        this.viewState = new ViewState();
        this._curState = null;
        this._bInited = true;
    }

    isInited(){
        return this._bInited;
    }

    initDAD(){
        if(!this._gameDiv){
            throw new Error('map div can not null!');
        }

        // 在管理员模式下  cnpm start 启动 不能 onDrop
        let gameEl = this._gameDiv;
        let self = this;
        gameEl.ondragenter = function (e) {
            console.log('ondragenter......');
            e.stopPropagation();
            e.preventDefault();
        };
        gameEl.ondragover = function (e) {
            console.log('ondragover......');
            e.stopPropagation();
            e.preventDefault();
        };
        gameEl.ondrop = function (e) {
            e.stopPropagation();
            e.preventDefault();
            self._doDrop(e);
        }
    }

    /**
     *  返回的是webgl坐标系下的坐标
     * @param e {MouseEvent}
     * @returns {cc.Vec2}
     */
    getPosFromEvent(e){
        let left = this._gameDiv.offsetLeft;
        let top = this._gameDiv.offsetTop;
        let x = e.clientX - left;
        let y = e.clientY - top;

        // TODO:暂时写死
        return cc.v2(x * 2,1600 -  2 * y);
    }

    _doDrop(e){
        console.log('e:',e);

        let dt = e.dataTransfer;
        let files = dt.files;

        if (files.length > 1) {
            settings.alert('只支持拖拽单个文件....');
            return;
        }

        // 拖的是 dirView 下的单个文件
        if(files.length < 1){

            let pos = this.getPosFromEvent(e);

            // 拖放进去的 装饰的路径
            let decoPath = dt.getData('img_path');
            if(!decoPath || decoPath.length < 1){
                settings.alert('请托拽正确的资源');
                return;
            }

            // TODO: 暂时还没有释放这些纹理
            //
            cc.assetManager.loadRemote(decoPath,(err,textrue)=>{
                if(err){
                    throw err;
                }
                let frame = new cc.SpriteFrame(textrue);

                let mapScene = editor.gameApp;
                mapScene.onAddDecoSprite(decoPath,frame,pos);
            });

            return;
        }

        // 拖放进去的json文件
        let file = files[0];
        let filePath = file.path;
        console.log('拖入文件:',filePath);
        let name = file.name;
        let extName = window.path.extname(name).toLowerCase();
        if(extName !== '.json'){
            settings.alert('只支持json文件');
            return;
        }
        this.importLevel(filePath);
    }

    importLevel(filePath){
        let content = window.fs.readFileSync(filePath,'utf8');
        let importJson;
        try{
            importJson = JSON.parse(content);
        }catch (e) {
            settings.alert('导入文件不是json格式!');
            return;
        }

        // 清空地图
        this.cleanAllMap();

        // chains
        let mapScene = editor.gameApp;

        // 显示导入的文件
        // cannos
        let mapView = this.getMapView();
        mapView.model.lvPath = filePath;

        let cannosData = importJson.cannos;
        mapView.parseCanno(cannosData);

        // bg
        let bgPath =  importJson.bg;
        mapScene.setBg(mapView.getBgLabelEl(),bgPath);

        // chain
        let version = importJson.v; // eslint-disable-line
        console.log('===关卡文件版本 version:',version);

        let lstChainData = importJson.chains;

        // 兼容. 这个对游戏影响不大
        if(importJson.sct > 0){
            mapScene.setChainType(G.ChainDrawMode.Line);
        }else{
            mapScene.setChainType(G.ChainDrawMode.Quad);
        }
        mapScene.parseChainDatas(lstChainData);

        let resDir = importJson.resDir;

        // deco view
        let decoView = this.getDecoView();
        let lstDecoData = importJson.deco; // eslint-disable-line
        let decoPromise = decoView.async_parseDeco(lstDecoData,resDir);

        // props 道具
        let propView = this.getPropView();
        let propData = importJson.props;
        propView.parseProp(propData);

        // cond 过关条件
        let passView = this.getPassView();
        let condData = importJson.cond;
        passView.parseCond(condData);

        // resDir
        let dirView = this.getDirView();
        dirView.setResDirPath(resDir);

        // ballControl
        let ballCountView = this.getBallCountView();
        ballCountView.parseBallCount(importJson);

        let self = this;
        decoPromise.then(function () {
            // 切换到 view state
            self.changeState(self.viewState);
            self.getMapView().getModel().state = UIConstants.State.View;
        }).catch(function () {
            settings.alert('解析 json 错误!');
        });
    }

    get gameApp(){
        return this._gameApp;
    }

    getDecoView(){
        return this.controlView.resView.decoView;
    }

    getInspectView(){
        return this.inspectView;
    }

    getBkpView(){
        return this.controlView.bkpView;
    }

    getPropView(){
        return this.controlView.settingView.propView;
    }

    getPassView(){
        return this.controlView.settingView.passView;
    }

    getBallCountView(){
        return this.controlView.settingView.ballCountView;
    }

    getMapView(){
        return this.controlView.mapView;
    }

    getDirView(){
        return this.controlView.resView.dirView;
    }

    getInspAnimView(){
        return this.inspectView.inspAnimView;
    }

    cleanAllMap(){
        let mapScene = editor.gameApp;
        mapScene.setCurSel(null);

        if(mapScene.lstChain.length > 1){
            // 有两个,先删除当前这个
            // mapScene.deleteChain();
            mapScene.removeChain(mapScene.curChain);

            let curChain = mapScene.curChain;
            curChain.clean();
            // curChain.updateChain();
        }else{
            let chain0 = mapScene.lstChain[0];
            chain0.clean();
            mapScene.setCurChain(chain0);
            // chain0.updateChain();
        }

        let bkpView = this.getBkpView();
        bkpView.reset();

        // 先删除背景 释放纹理
        mapScene.removeBg();
        let mapView = this.getMapView();
        mapView.reset();

        // 还需要清除 ui 相关
        this.inspectView.updateInspectView(null);

        // 道具信息
        let propView = this.getPropView();
        propView.reset();

        // 过关设置
        let passView = this.getPassView();
        passView.reset();

        // 出球设置
        let ballCountView = this.getBallCountView();
        ballCountView.reset();

        // dirView
        let dirView = this.getDirView();
        dirView.setResDirPath('');

        // 包含了 删除  deco
        let decoView = this.getDecoView();
        decoView.reset();

        // 同时,会清除所有的操作
        this.history.clean();
    }


    exportLevel(finalPath){
        /**
         *  导出的文件格式:
         *
         *  V1.0.1 版格式
         *  {
         *      v:"1.0.1", // 版本号
         *      sct:1, // chainDrawMode  0:Line,1:Quad
         *      chains:[
         *              {
         *                  ps:[{x:xx,y:xx},{x:xx,y:xx}],
         *                  bkpIds:[
         *                      {s:xx,e:xx,type:0/1/2},
         *                  ],
         *               }
         *      ], // 轨道信息
         *      cannos:{
         *          type:0/1/2/3/4/5/6/7, 发射器类型
         *          size:xx, // 表示移动范围
         *          data:[
         *          {
         *             x:xx,
         *             y:xx,
         *             degress:xx,
         *             name:'xx.png'，
         *             enable:1, // 1:表示启用, 0: 表示未启用 可以直接根据类型来判断是否启用
         *          },
         *          {
         *             x:xx,
         *             y:xx,
         *             degress:xx,
         *             name:'xx.png'，
         *             enable:1, // 1:表示启用, 0: 表示未启用
         *          },
         *          ],
         *      },
         *      bg:'xx.png',
         *      deco:[
         *          {x:xx,y:xx,degress:xx,hole:false},
         *      ], // 装饰
         *      props:{
         *          fog:1,
         *          colorful:1,
         *          lighting:1,
         *          meteor:1，
         *          bomb:1,
         *          arrow:1,
         *      }, // 道具
         *      cond:{
         *          time:xx,
         *          score:xx,
         *          anim:xx,
         *          d_1:xx,
         *          d_2:xx,
         *          d_3:xx,
         *          d_4:xx,
         *      },
         *      resDir:'', //资源文件路径
         *      tc:3  // 球的种类  (typeCount)
         *      bc:20  // 球的个数  (ballCount)
         *      fc:1   // 冰球个数
         *      sc:1  // 石头球个数
         *  }
         */

        let mapScene = this.gameApp;
        let mapView = this.getMapView();

        let retObj = {};
        retObj.v = '1.0.2'; // 当前导出文件版本好
        retObj.sct = mapScene.getChainbDrawMode();

        retObj.chains = mapScene.getChainModel(); // arr
        retObj.cannos = mapView.getCannoModel(); // obj
        retObj.bg = mapView.getBgLabelEl().value.trim();    // string

        let decoView = this.getDecoView();
        retObj.deco = decoView.getDecoModel();  // arr

        let propView = this.getPropView();
        retObj.props = propView.getPropModel(); // obj

        let passView = this.getPassView();
        retObj.cond = passView.getCondModel(); // obj

        let dirView = this.getDirView();
        retObj.resDir = dirView.getResDirPath();

        let ballCountView = this.getBallCountView();
        retObj.tc = ballCountView.model.typeCount;
        retObj.bc = ballCountView.model.ballCount;
        retObj.fc = ballCountView.model.frozenCount;
        retObj.sc = ballCountView.model.stoneCount;
        retObj.dc = ballCountView.model.deadCount;
        retObj.ballSpeed = ballCountView.model.ballSpeed;

        // 写入文件
        let fs = window.fs;
        fs.writeFileSync(finalPath, JSON.stringify(retObj));
        settings.alert('保存成功!');
    }

    getCurState(){
        return this._curState;
    }

    changeState(newState){
        if(!newState){
            throw new Error(`newState is null!`);
        }

        if(this._curState){
            this._curState.onExit();
        }
        newState.onEnter();
        this._curState = newState;
    }

    updateStateByValue(value){
        switch (value) {
            case UIConstants.State.EditSelNode:
                this.changeState(this.editChainState);
                break;
            case UIConstants.State.EditHoleOrBridge:
                this.changeState(this.editHoleBridgeState);
                break;
            case UIConstants.State.EditProp:
                this.changeState(this.editObjState);
                break;
            case UIConstants.State.View:
                this.changeState(this.viewState);
                break;
            default:
                throw new Error(`unknow state value:${value}`);
        }
    }

    isViewState(){
        return this._curState === this.viewState;
    }

    isEditChainState(){
        return this._curState === this.editChainState;
    }

    isEditObjState(){
        return this._curState === this.editObjState;
    }

    execute(cmd){
        this.history.execute(cmd);
    }
}


module.exports = EditorView;
